(in-package "ACL2")
(include-book "grid")
(include-book "base-utils")
;;;Functionality for converting a wolfram code
;;;to what we're calling a "wolfram table" and querying
;;;the wolfram table for whether a particular state
;;;corresponds to a situation where a cell should
;;;be born or stay alive in the next generation
;;;
;;;Glossary
;;;
;;;Situation number: TODO need a less terrible name for this
;;;     An integer that uniquely captures one of the 8 possible
;;;     states for a cell to be in with respect to its neighbors
;;;     in an elementary CA.  This number corresponds to the 
;;;     "place value" of that situation in the computation of a
;;;     wolfram code. It's equivalent to 
;;;         1 if the right cell is alive + 
;;;         2 if the middle cell is alive +
;;;         4 if the left cell is alive
;;;
;;;
;;;Wolfram table: A list of 8 bools, each corresponding to whether
;;;     the cell in the center should be alive in the
;;;     situation number equal to its index in the list

;;Given a situation number, compute whether it corresponds
;;to one where the cell is currently dead (and therefore
;;has the potential of being born in the next step)
(defun is-index-of-possible-birth-state (index)
    (< (mod index 4) 2))


;;Convert a list of ints to nil or t
;;(0 is nil, anything else is t)
(defun ints->bools* (ints)
    (if (endp ints)
        nil
        (cons (if (equal (car ints) 0)
                nil
                t) 
            (ints->bools* (cdr ints)))))

;;convert a bool expression to 1 (t) or 0 (nil)
(defun bool->int (b)
    (if b
        1
        0))

;;Deliver a list of 8 bools, each corresponding to whether
;;the cell in the center should be alive in the
;;situation number equal to its index in the list
(defun parse-wolfram-code (wolfram-code)
    (let* ((selections (pad-to-size 8 (nat->numerals 2 wolfram-code))))
        (ints->bools* selections)))

;;Given the status of a position and its neighbors on the left and
;;right, compute its situation number
(defun get-situation-number-explicit (lpos-alive pos-alive rpos-alive)
    (+  (* 2 (+ 
                (* 2 (bool->int lpos-alive)) 
                (bool->int pos-alive))) 
        (bool->int rpos-alive)))

;;Compute the situation number of a position in a grid
(defun get-situation-number (elem-grid pos)
    (let* ((right (1+ pos))
            (left (1- pos))
            (right-has-cell (elementary-grid-get elem-grid right))
            (left-has-cell (elementary-grid-get elem-grid left))
            (pos-has-cell (elementary-grid-get elem-grid pos)))
        (get-situation-number-explicit left-has-cell 
            pos-has-cell right-has-cell)))

;;get all the first elements of the lists in a list
(defun get-cars* (lst)
    (if (endp lst)
        nil
        (cons (caar lst)
            (get-cars* (cdr lst)))))

;;Flatten an elementary grid into just 
;;a list of live positions
(defun flatten-elementary-grid (grid)
    (get-cars* (avl-flatten grid)))

;;Compute whether a given situation corresponds
;;to a cell's existence or nonexistence for
;;the given wolfram table
(defun check-situation (wolf-table sit-number)
    (nth sit-number wolf-table))
